package defineProduct.model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

//import com.sun.xml.internal.ws.org.objectweb.asm.Type;


import model.ConnectionPool;
import model.DatabaseException;


public class ItemBean {
	private long id;
	private String description;
	private double promotionalPrice;
	private double price;
	private double wholesalePrice;
	private int brandId;
	private int producerId;
	private int supplierId;
	private Map<Long, Integer> materialIdToPercent = new HashMap<Long, Integer>();
	private Set<Long> presentIds = new HashSet<Long>();
	private Set<String> features = new HashSet<String>();
	private Set<Long> categoryIds = new HashSet<Long>();
	private Map<Long, HashMap<Long, Integer>> colorIdToSizeIdToCount = new HashMap<Long, HashMap<Long, Integer>>();
	private Map<Long, HashSet<String>> colorIdToFigurePaths = new HashMap<Long, HashSet<String>>();
	private TreeSet<Long> sizes = new TreeSet<Long>();
	private Map<Long, HashSet<String>> sizeDescription = new HashMap<Long, HashSet<String>>();
	public ItemBean(String description, double promotionalPrice, double price,
			double wholesalePrice, int brandId, int producerId, int supplierId) {
		super();
		this.description = description;
		this.promotionalPrice = promotionalPrice;
		this.price = price;
		this.wholesalePrice = wholesalePrice;
		this.brandId = brandId;
		this.producerId = producerId;
		this.supplierId = supplierId;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}
	
	public boolean isFigureUploaded(long colorId){
		boolean isFigureUploaded = false;
		if(colorIdToFigurePaths.containsKey(colorId)){
			isFigureUploaded = true;
		}
		
		return isFigureUploaded;
	}
	public void addColorFigurePath(Long id, String figurePath){
		HashSet<String> figures = colorIdToFigurePaths.getOrDefault(id, new HashSet<String>());
		figures.add(figurePath);
		colorIdToFigurePaths.put(id, figures);
	}
	public void removeColorFigurePath(Long id, String figurePath){
		HashSet<String> figures = colorIdToFigurePaths.getOrDefault(id, new HashSet<String>());
		figures.removeIf(x->x.equals(figurePath));
		colorIdToFigurePaths.put(id, figures);
	}
	public void addMaterialPercent(long materialId, int percent){
		this.materialIdToPercent.put(materialId, percent);
	}
	public void addPresent(long presentId){
		this.presentIds.add(presentId);
	}
	public void addFeature(String feature){
		this.features.add(feature);
	}
	public void addCategory(long categoryId){
		this.categoryIds.add(categoryId);
	}
	
	public void addColorSizeCount(long colorId, long sizeId, int count){
		HashMap<Long, Integer> sizeCount = this.colorIdToSizeIdToCount.getOrDefault(colorId, new HashMap<Long,Integer>());
		sizeCount.put(sizeId, count);
		this.colorIdToSizeIdToCount.put(colorId, sizeCount);
		this.sizes.add(sizeId);
	}
	
	public Set<Long> getSizes(){
		return Collections.unmodifiableSortedSet(this.sizes);
	}
	
	public void addSizeDescripton(long id, String description){
		HashSet<String> descriptions= this.sizeDescription.getOrDefault(id, new HashSet<String>());
		descriptions.add(description);
		this.sizeDescription.put(id, descriptions);
	}
	
	private  void insertIntoItems(Connection con) throws SQLException{
		String query = "insert into Items(description, price, promotional_price, "
				+ "whole_sale_price, supplier_id, producer_id, brand_id) values(?,?,?,?,?,?,?)";
		ResultSet rs = null;
		long id = -1;
		try (PreparedStatement preparedStatement = con.prepareStatement(query,
				new String[] { "id" });) {

			preparedStatement.setString(1, description);
			preparedStatement.setDouble(2, price);
			if(promotionalPrice!=0){
				preparedStatement.setDouble(3, promotionalPrice);
			}else{
				preparedStatement.setNull(3, Types.DOUBLE);
			}
			if(wholesalePrice!=0){
				preparedStatement.setDouble(4, wholesalePrice);
			}else{
				preparedStatement.setNull(4, Types.DOUBLE);
			}
			preparedStatement.setInt(5, supplierId);
			preparedStatement.setInt(6, producerId);
			if(brandId!=0){
				preparedStatement.setDouble(7, brandId);
			}else{
				preparedStatement.setNull(7, Types.BIGINT);
			}
			preparedStatement.executeUpdate();
			rs = preparedStatement.getGeneratedKeys();
			if (rs != null && rs.next()) {
				id = rs.getLong(1);
				this.setId(id);
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}
	}
	
	private  void insertIntoItemCategories(Connection con) throws SQLException{
		String query = "insert into Item_Categories(item_id,category_id) values(?,?)";
		ResultSet rs = null;
		try (PreparedStatement preparedStatement = con.prepareStatement(query);) {
			for(Long categoryId: categoryIds){
				preparedStatement.setLong(1, id);
				preparedStatement.setLong(2, categoryId);
				preparedStatement.executeUpdate();
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}
	}
	
	private  void insertIntoItemMaterials(Connection con) throws SQLException{
		String query = "insert into Item_Materials(item_id,material_id, percentage) values(?,?,?)";
		ResultSet rs = null;
		try (PreparedStatement preparedStatement = con.prepareStatement(query);) {
			Set<Long> materials = materialIdToPercent.keySet();
			for(Long materialId: materials){
				preparedStatement.setLong(1, id);
				preparedStatement.setLong(2, materialId);
				preparedStatement.setInt(3, materialIdToPercent.get(materialId));
				preparedStatement.executeUpdate();
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}
	}
	
	private  void insertIntoItemPresents(Connection con) throws SQLException{
		String query = "insert into Item_Presents(item_id,present_id) values(?,?)";
		ResultSet rs = null;
		try (PreparedStatement preparedStatement = con.prepareStatement(query);) {
			for(Long presentId: presentIds){
				preparedStatement.setLong(1, id);
				preparedStatement.setLong(2, presentId);
				preparedStatement.executeUpdate();
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}
	}
	
	private  void insertIntoFeatures(Connection con) throws SQLException{
		String query = "insert into Features(item_id,description) values(?,?)";
		ResultSet rs = null;
		try (PreparedStatement preparedStatement = con.prepareStatement(query);) {
			for(String feature: features){
				preparedStatement.setLong(1, id);
				preparedStatement.setString(2, feature);
				preparedStatement.executeUpdate();
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}
	}
	
	
	
	private  void insertIntoFigures(Connection con) throws SQLException{
		String query = "insert into Figures(item_id, path,color_id) values(?,?,?)";
		ResultSet rs = null;
		try (PreparedStatement preparedStatement = con.prepareStatement(query);) {
			Set<Long> colors =  colorIdToFigurePaths.keySet();
			Set<String> paths = null;
			for (long colorId: colors){
				paths = colorIdToFigurePaths.get(colorId);
				for(String path: paths){
					preparedStatement.setLong(1, id);
					preparedStatement.setString(2, path);
					preparedStatement.setLong(3, colorId);
					preparedStatement.executeUpdate();
				}	
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}
	}
	
	private  void insertIntoClothingInventory(Connection con) throws SQLException{
		String query = "insert into Clothing_Inventory(item_id, size_id, color_id, count) values(?,?,?,?)";
		ResultSet rs = null;
		try (PreparedStatement preparedStatement = con.prepareStatement(query);) {
			Set<Long> colors =  colorIdToSizeIdToCount.keySet();
			Map<Long,Integer> sizeToCount = null;
			Set<Long> sizes = null;
			for(Long color :colors){
				sizeToCount = colorIdToSizeIdToCount.get(color);
				sizes = sizeToCount.keySet();
				for(long size : sizes){
					preparedStatement.setLong(1, id);
					preparedStatement.setLong(2, size);
					preparedStatement.setLong(3, color);
					preparedStatement.setInt(4, sizeToCount.get(size));
					preparedStatement.executeUpdate();
				}	
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}
	}
	
	private  void insertIntoAdditionalSizes(Connection con) throws SQLException{
		String query = "insert into Additional_Sizes(item_id,size_id, additional_size_description) values(?,?,?)";
		ResultSet rs = null;
		try (PreparedStatement preparedStatement = con.prepareStatement(query);) {
			Set<Long> sizes = sizeDescription.keySet();
			Set<String> descriptions;
			for(long size: sizes){
				descriptions = sizeDescription.get(size);
				for(String description: descriptions){
					preparedStatement.setLong(1, id);
					preparedStatement.setLong(2, size);
					preparedStatement.setString(3, description);
					preparedStatement.executeUpdate();
				}
			}
		} finally {
			if (rs != null) {
				rs.close();
			}
		}
	}
	public void addToDB() throws DatabaseException{
		Connection con=null;
		try {
			con = ConnectionPool.getConnection();
			con.setAutoCommit(false);
			insertIntoItems(con);
			insertIntoItemCategories(con);
			insertIntoItemMaterials(con);
			insertIntoItemPresents(con);
			insertIntoFeatures(con);
			insertIntoFigures(con);
			insertIntoClothingInventory(con);
			insertIntoAdditionalSizes(con);
			con.commit();
		} catch (SQLException e) {
			try {
				if(con!=null){
					con.rollback();
				}
			} catch (SQLException e1) {

				throw new DatabaseException(e1);
			}
			throw new DatabaseException(e);
		}finally{
			try {
				if(con!=null){
					con.close();
				}
			} catch (SQLException e) {
				throw new DatabaseException(e);
			}
		}
	}
	
//	public static void main(String[] args) {
//		
//	}
}
